﻿using System;
using System.IO;
using System.Threading;

public sealed class FileWatcher : IDisposable
{
    private const int TimeoutMillis = 500;

    // Fields
    private FileInfo m_file;
    private WatchedFileChangedCallback m_callback;
    private FileSystemWatcher m_watcher;
    private Timer m_timer;

    // Methods
    public FileWatcher( FileInfo file, WatchedFileChangedCallback callback )
    {
        this.m_file = file;
        this.m_callback = callback;
        this.m_watcher = new FileSystemWatcher();
        this.m_watcher.Path = this.m_file.DirectoryName;
        this.m_watcher.Filter = this.m_file.Name;
        this.m_watcher.NotifyFilter = NotifyFilters.CreationTime | NotifyFilters.LastWrite | NotifyFilters.FileName;
        this.m_watcher.Changed += new FileSystemEventHandler( this.Watch_OnChanged );
        this.m_watcher.Created += new FileSystemEventHandler( this.Watch_OnChanged );
        this.m_watcher.Deleted += new FileSystemEventHandler( this.Watch_OnChanged );
        this.m_watcher.Renamed += new RenamedEventHandler( this.Watch_OnRenamed );
        this.m_watcher.EnableRaisingEvents = true;
        this.m_timer = new Timer( new TimerCallback( this.OnWatchedFileChanged ), null, Timeout.Infinite, Timeout.Infinite );
    }

    public delegate void WatchedFileChangedCallback( FileInfo file );

    private void Watch_OnChanged( object source, FileSystemEventArgs e )
    {
        this.m_timer.Change( TimeoutMillis, Timeout.Infinite );
    }

    private void Watch_OnRenamed( object source, RenamedEventArgs e )
    {
        this.m_timer.Change( TimeoutMillis, Timeout.Infinite );
    }

    private void OnWatchedFileChanged( object state )
    {
        this.m_callback.Invoke( this.m_file );
    }

    public void Dispose()
    {
        this.m_watcher.Dispose();
    }
}

